/*
Copyright 2005  Vitaliy Shevchuk (shevit@users.sourceforge.net)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

package org.ajaxanywhere;

import org.ajaxanywhere.parser.HTMLBlock;
import org.ajaxanywhere.parser.ResponseParser;
import org.ajaxanywhere.parser.ResponseParserFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
import java.util.logging.Logger;

/**
 * Date: 23 juil. 2005 Time: 21:50:21
 */
public class XMLBuilder implements AAConstants {
	private final static Logger LOGGER = Logger.getLogger(XMLBuilder.class.getName());

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void sendZones(BufferResponseWrapper bufferResponseWrapper, Set refreshZones) {
		StringBuilder xml = new StringBuilder(8192);
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>").append("<").append(AA_XML_ZONES)
				.append(">");

		List scripts = new ArrayList();
		Set images = new HashSet();

		for (Iterator iterator = refreshZones.iterator(); iterator.hasNext();) {
			String zone = (String) iterator.next();
			String content = AAUtils.getZoneContent(zone, bufferResponseWrapper);

			// if zone added to refresh list but not present in content, then exclude zone
			// info in response
			if (content == null) {
				continue;
			}

			HTMLBlock bean = handleZoneContent(content);

			xml.append("<").append(AA_XML_ZONE).append(" ").append(AA_XML_NAME).append("=\"").append(zone).append("\"")
					.append(">");
			xml.append("<![CDATA[");
			xml.append(bean.getHtmlContent());
			xml.append("]]>");
			xml.append("</").append(AA_XML_ZONE).append(">");

			scripts.addAll(bean.getScriptContents());
			images.addAll(bean.getImages());
		}

		for (int i = 0; i < scripts.size(); i++) {
			String script = (String) scripts.get(i);
			int posScriptEnd = script.indexOf('>');
			if (posScriptEnd != -1)
				script = script.substring(posScriptEnd + 1);

			xml.append("<").append(AA_XML_SCRIPT).append(">");
			xml.append("<![CDATA[");
			xml.append(script);
			xml.append("]]>");
			xml.append("</").append(AA_XML_SCRIPT).append(">");
		}

		for (Iterator it = images.iterator(); it.hasNext();) {
			String image = (String) it.next();

			xml.append("<").append(AA_XML_IMAGE).append(">");
			xml.append("<![CDATA[");
			xml.append(image);
			xml.append("]]>");
			xml.append("</").append(AA_XML_IMAGE).append(">");
		}
		xml.append("</").append(AA_XML_ZONES).append(">");

		sendDOMDocument(bufferResponseWrapper.getOriginalResponse(), xml.toString());
	}

	/**
	 * Find out script, image tags in content, wrapp them in new XML node
	 * 
	 * @param content
	 * @param zoneNode
	 * @param doc
	 * @param scripts
	 * @param images
	 * @param root
	 */
	private static HTMLBlock handleZoneContent(String content) {
		ResponseParser parser = ResponseParserFactory.getInstance().getParser();
		return parser.parse(content);
	}

	private static void sendDOMDocument(HttpServletResponse originalResponse, String doc) {
		try {
			OutputStream out = originalResponse.getOutputStream();
			String encoding = originalResponse.getCharacterEncoding();
			if (encoding == null) {
				out.write(doc.getBytes());
				LOGGER.warning("charset is not set for response, this will use default String.getBytes()");
			} else {
				out.write(doc.getBytes(encoding));
			}
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void handleError(HttpServletResponse response, Throwable exception) {
		StringBuilder xml = new StringBuilder(1024);
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>").append("<").append(AA_XML_ZONES)
				.append(">");
		xml.append("<").append(AA_XML_EXCEPTION).append(">");
		xml.append("<![CDATA[");

		StringWriter sw = new StringWriter();
		exception.printStackTrace(new PrintWriter(sw));
		xml.append(sw.toString());

		xml.append("]]>");
		xml.append("</").append(AA_XML_EXCEPTION).append(">");

		sendDOMDocument(response, xml.toString());
	}

	public static void sendRedirect(BufferResponseWrapper bufferResponseWrapper) {
		StringBuilder xml = new StringBuilder(1024);
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>").append("<").append(AA_XML_ZONES)
				.append(">");
		xml.append("<").append(AA_XML_REDIRECT).append(">");
		xml.append("<![CDATA[");
		xml.append(bufferResponseWrapper.getRedirect());
		xml.append("]]>");
		xml.append("</").append(AA_XML_REDIRECT).append(">");

		sendDOMDocument(bufferResponseWrapper.getOriginalResponse(), xml.toString());
	}
}
